package com.br4mmie.asciistory.map;

import java.io.*;
import java.util.*;

import com.br4mmie.asciistory.CharImage;
import com.br4mmie.asciistory.FileGetter;
import com.br4mmie.asciistory.characters.NPC;
import com.br4mmie.asciistory.mission.Item;
import com.br4mmie.asciistory.mission.Mission;


/**
 * MapLoader loads a map.. that's it. Live with it.
 * @author Ken Veenstra
 * 		   Bram Buurlage
 */
public class MapLoader 
{
	private char[][] 	mapData;
	private boolean[][]	collisions;
	private Random		random = new Random();
	private String		filename;
	
	private ArrayList<Character> attrChars = new ArrayList<Character>();
	private ArrayList<Character> wallChars = new ArrayList<Character>();
	private ArrayList<Item> items = new ArrayList<Item>();
	private ArrayList<Integer> itemCount = new ArrayList<Integer>();
	private ArrayList<String[]> npcdata = new ArrayList<String[]>();
	private ArrayList<Encounter> encounters = new ArrayList<Encounter>();
	private ArrayList<Portal> portals = new ArrayList<Portal>();
	
	private int		playerX;
	private int		playerY;
	
	/**
	 * Constructor, loads a map from a file and fills this instance with the content of that map
	 * @param filename 	The file to load
	 * @param attrChars These are the characters that have an attribute in the map file. 
	 * 					A portal ('P') for example, has an attribute that references to another map 
	 * @param wallChars These are the characters that should be marked as a wall.
	 */
	public MapLoader(String filename) throws NumberFormatException, IOException
	{
		this.filename = filename;
		loadFromFile(filename);
	}
	/**
	 * this constructor does the same as the above, 
	 * but it overrides the default spawn point, to the one specified in spawnX and spawnY
	 * @param spawnX the overriden x location
	 * @param spawnY the overriden y location
	 */
	public MapLoader(String filename, int spawnX, int spawnY) throws NumberFormatException, IOException
	{
		this.filename = filename;
		loadFromFile(filename);
		
		playerX = spawnX;
		playerY = spawnY;
	}
	
	private String readAttribute(char[] values, int i) 
	{
		String attribute = "";
		int end = i+1;
		
		while (end < values.length && values[end] != ':') 
		{
			attribute += (char)values[end];
			end++;
		}
		
		return attribute;
	}
	private void loadLine(String line, int width, int y)
	{
		char[] values = line.toCharArray();
		ArrayList<String> fileAttributes = new ArrayList<String>();
		
		int i=0;
		while (i < values.length)
		{
			if (values[i] == ':') fileAttributes.add(readAttribute(values, i));
			i++;
		}
		
		i=0;
		for (int x=0; x<width; x++)
		{
			mapData[y][x] = values[x];
			for (int j=0; j<attrChars.size(); j++)
			{
				if (mapData[y][x] == attrChars.get(j))
				{
					String[] portalData = fileAttributes.get(i++).split(",");
					Portal portal = new Portal(
							portalData[0], x, y,
							Integer.parseInt(portalData[1]), 
							Integer.parseInt(portalData[2]));
					
					CharImage portalImage = new CharImage(1,1);
					portalImage.fill('P');
					portal.setImage(portalImage);
					
					portals.add(portal);
				}
			}
			for (int j=0; j<wallChars.size(); j++)
			{
				if (mapData[y][x] == wallChars.get(j))
				{
					collisions[y][x] = true;
				}
			}
		}
	}
	private void loadFromFile(String fileName) throws NumberFormatException, IOException
	{
		BufferedReader reader = new BufferedReader(new FileReader(FileGetter.getFilename(fileName)));
		
		String line = null;
		while (true)
		{
			line = reader.readLine();
			if (line.startsWith("s "))
			{
				random = new Random(Integer.parseInt(line.substring(2)));
			} else if (line.startsWith("i "))
			{
				String[] content = line.split(" ");
				items.add(Item.fromFile(content[1]));
				itemCount.add(Integer.parseInt(content[2]));
			} else if (line.startsWith("c "))
			{
				wallChars.add(line.charAt(2));
			} else if (line.startsWith("a "))
			{
				attrChars.add(line.charAt(2));
			} else if (line.startsWith("N "))
			{
				String content = line.substring(2);
				npcdata.add(content.split(" "));
			} else if (line.startsWith("e "))
			{
				String[] content = line.split(" ");
				encounters.add(new Encounter(content[1], Double.parseDouble(content[2])));
			}
			
			
			
			if (line.startsWith("m "))
			{
				break;
			}
		}
		
		int width = 	Integer.parseInt(line.substring(2));
		int height = 	Integer.parseInt(reader.readLine());
		playerX = 		Integer.parseInt(reader.readLine());
		playerY = 		Integer.parseInt(reader.readLine());
		mapData = 		new char	[height][width];
		collisions = 	new boolean	[height][width];
		
		for (int y=0; y<height; y++)
		{
			loadLine(reader.readLine(), width, y);
		}
	}
	
	/**
	 * Creates a map from the internal data.
	 * @return Returns an instance of Map
	 */
	public Map createMap()
	{
		int height = mapData.length;
		String mapDataString = "";
		
		for (int y=0; y<height; y++)
		{
			mapDataString += new String(mapData[y]) + "\n";
		}

		Map m = new Map(mapData[0].length, mapData.length, mapDataString, collisions, playerX, playerY);
		m.setFilename(filename);
		
		for (Portal portal: portals) m.addMapObject(portal);
		for (String[] npcData: npcdata)
		{
			try 
			{
				CharImage image = new CharImage(1,1);
				image.setImage(npcData[1]);
				Mission mission = new Mission(npcData[4]);
				
				NPC npc = new NPC(npcData[0], mission);
				npc.setImage(image);
				npc.setX(Integer.parseInt(npcData[2]));
				npc.setY(Integer.parseInt(npcData[3]));
				
				m.addMapObject(npc);
			} catch (Exception e) 
			{
				e.printStackTrace();
			}
		}
		for (Encounter e: encounters)
		{
			m.addEncounter(e);
		}
		for (int i=0; i<items.size(); i++)
		{
			for (int j=0; j<itemCount.get(i); j++)
			{
				int x = 0;
				int y = 0;
				while (m.getCollision(x, y))
				{
					x = random.nextInt(m.getWidth());
					y = random.nextInt(m.getHeight());
				}
				
				m.addItem(items.get(i), x, y);
			}
		}
		
		return m;
	}
}
